/* ECUCleanup12082017 *by Pete Stanaitis *NOTE*** This is still experimental code! * It is currently running on a 2 cylinder Onan generator set */ #include #include //-------------------------------------------- //CTC Libraries, which are NOT used, are they? #include #include //--------------------------------------------------------------------------- volatile unsigned long _hits; // volatile unsigned long currentMicros; volatile unsigned long previousStartTime; const int coilTime = 6000; const int timeLostinISR = (1980 +(coilTime-3000)); int rpm =0; volatile unsigned long elapsedTime; volatile unsigned long etCorrected; const int timer1Pin = 7; const int triggerPin = 8; const int strobeLed = 13; const int advancePot = A2; const int advancePot5KGood = A3; int advanceDegrees; int previousAdvanceDegrees; int coilPulsePot = A1; volatile unsigned long delta; volatile unsigned long advance = 0; volatile float oneDegree; //The time it takes for the crank to advance one degree at the current rpm, I think. volatile boolean sparkOn = false; //Used to shut off sparks when not wanted. volatile int sparkTimingDegrees = 0; //LCD read request button assignment int LCDReadPin = 10; //--------------------------------------------------------------------------- LiquidCrystal_I2C lcd(0x27, 2, 1, 0,4 ,5, 6, 7, 3, POSITIVE); // set the LCD I2C address //---------------------------------------------------------------------------- void setup() { pinMode(triggerPin, OUTPUT); pinMode(timer1Pin, OUTPUT); pinMode(strobeLed, OUTPUT); pinMode(coilPulsePot, INPUT); pinMode(advancePot, INPUT); pinMode(LCDReadPin, INPUT); digitalWrite(LCDReadPin, HIGH); Serial.begin(115200); //--------------------------- lcd.begin(20,4); lcd.backlight(); lcd.clear(); lcd.begin(20, 4); // set up the LCD's number of columns and rows: lcd.print("RPM: S_hits advDegs"); lcd.setCursor(0, 2); lcd.print("Loop uSec"); //-------------------------- //Setup stuff for LCD read request pinMode(LCDReadPin, INPUT); attachInterrupt(0, beam_interrupt, RISING); pinMode(3, INPUT); attachInterrupt(1, beam_interruptN, RISING); //--------------------Timer Compare Match Code--------------------------- // initialize Timer1 cli(); // disable global interrupts while doing this TCCR1A = 0; // set entire TCCR1A register to 0 TCCR1B = 0; // same for TCCR1B // set compare match register to desired timer count: OCR1A = advance; //Initially setting OCR1A to zero because advance is declared as zero TCCR1B |= (1 << WGM12); // turn on CTC mode TCCR1B = _BV(CS00) | _BV(CS01); //Prescale = 64, but a little faster, maybe TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt: sei(); // enable global interrupts: } //----------------------------------------------------------------------- //Interrupt 0 ISR //Capture the 3 South Hall Semsor Falling Pulse for use in reading RPMs //Not used at present //---------------------------------------------------------------------- void beam_interrupt() //Capture 3 South magnets, Hall Effect sensor Falling pulse, { ++_hits; } //Interrupt 1 ISR //Capture the North Hall Sensor signal for use in trigger signal and also //use it in reading RPMs //------------------------------------------------------------------------ void beam_interruptN() { //Develop "oneDegree" by counting the time between N Magnets on the rotor //This is THE KEY value I use to calculate ignition timing and rpm unsigned long currentMicros = micros(); elapsedTime = (currentMicros- previousStartTime); etCorrected =elapsedTime +timeLostinISR; oneDegree = etCorrected/360.0; previousStartTime = currentMicros; //Start timer1, using Prescale value of 64 TCCR1B = _BV(CS00) | _BV(CS01); } //-------------------------------------------------- //Timer1 Compare Match ISR: This routine fires at the end of the icnition timing delay period ISR(TIMER1_COMPA_vect) { //global disable interrupts cli(); TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // Stop the counter TCNT1 = 0; //Rest the counter to zero digitalWrite(7, !digitalRead(7)); //This line is here for debugging, only to toggle an LED on Pin 7 //whenever timer1 reaches compare match to prove that the timer IS working makeSparks(); //Coil charging function. sei(); //Global enable interrupts } //------------------------------------------------------------------------------- //Here's where the sparks are made; Coil Charging begins for a set time, //times out, and ends with a spark and a Strobe LED void makeSparks() { if(sparkOn) { digitalWrite(triggerPin, HIGH); //This is where coil charging begins delayMicroseconds(coilTime); //This fixes Coil Charge peroid digitalWrite(triggerPin, LOW); //This is where the spark actually occurs. digitalWrite(strobeLed, HIGH); delayMicroseconds(50); //This is the on-period for the strobe. digitalWrite(strobeLed, LOW); } } //--------------Main Loop To Calculate RPM, Update LCD Display and Serial Monitor---------------- void loop() { //Beginning of Code to measure loop time unsigned long startLoopCount = micros(); //End of Code to measure loop time //Loop stuff for LCD read request if (digitalRead(LCDReadPin) == LOW) { displayRPM_LCD(); digitalWrite(LCDReadPin, HIGH); } //Read advance Degrees Pot //advanceDegrees = analogRead(advancePot); //advanceDegrees = constrain(advanceDegrees, 200, 1023); //advanceDegrees = map(advanceDegrees, 0, 1023, 14, -60);//Nov. 13, 2017: Need the constrain & "+14" to deal with noisy pot //Read advance Degrees 5K Ohm Pot (advancePot5KGood) advanceDegrees = analogRead(advancePot5KGood); advanceDegrees = map(advanceDegrees, 0, 1023, 0, -60);//Nov. 23, 2017: Installed a good 5K ohm pot if (advanceDegrees != previousAdvanceDegrees) {displayRPM_LCD(); } previousAdvanceDegrees = advanceDegrees; //make oneDegree //etCorrected =elapsedTime +timeLostinISR; // oneDegree = etCorrected/360.0; rpm =1000000 * 60/(oneDegree * 360); // time for one revolution; advance = ((((360.0 + sparkTimingDegrees)* oneDegree)-coilTime)/4.0); //This divide by 4 works well, //but still gives me OCR1A overlfow at about 127 rpm, but I can live with that. OCR1A = advance; //displayRPM_LCD(); //Only turned on for testing. Takes too long!!! //displayRPM_Serial(); //Much shorter than I2C LCD. //Ignition delay calculations here: //--------------------------------- if (rpm <200) { //0 to 200 rpms; too slow, no sparks sparkOn = false; sparkTimingDegrees = 10; } else if (rpm >= 200) { // 200 to max rpms; running sparkOn = true; sparkTimingDegrees = advanceDegrees; } //End ignition delay code //----------------------- //Last part of Code to measure loop time unsigned long end = micros(); delta = end - startLoopCount; //End of Code to measure loop time } //------------------------------------------------------------ //End of the Loop-----End of the Loop----End Of The Loop==== //----------------------------------------------------------- void displayRPM_LCD() //IF it is turned on!!! { lcd.setCursor(0, 1); lcd.print(" "); //To clear the previous reading lcd.setCursor(0, 1); lcd.print(rpm); lcd.print(" "); lcd.print(_hits); lcd.setCursor(15, 1); lcd.print(" "); lcd.setCursor(15, 1); lcd.print(advanceDegrees); lcd.setCursor(0, 3); lcd.print(" "); lcd.setCursor(0, 3); lcd.print(delta); } void displayRPM_Serial() { /* Serial.print(rpm); Serial.print(" "); Serial.print(delta); Serial.print(" "); Serial.print(oneDegree); Serial.print(" "); Serial.print(_hits); Serial.print(" "); Serial.print(OCR1A/rpm); Serial.print(" "); Serial.println(rpm/OCR1A); */ Serial.println(oneDegree); }